﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "CreateGBMPFamilyInstanceAction.h"

#include "GcmpCommandNames.h"
#include "GbmpUiPlatformCommandIds.h"
#include "GbmpBuiltInParameterDefinitions.h"
#include "IActionManager.h"

// GCMP API
#include "ICommandManager.h"
#include "IUserTransaction.h"
#include "ISnap.h"
#include "IDocument.h"
#include "IElementBasicInformation.h"
#include "IGraphicsNodeReference.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "IInstanceType.h"
#include "IInstance.h"
#include "IFamily.h"
#include "IFamilyType.h"
#include "IParameter.h"
#include "IParameterValueCurveByPoints.h"
#include "IPointPickContext.h"
#include "IPicker.h"
#include "IPickFilter.h"


#include "IUiDocumentViewManager.h"
#include "IUiDocument.h"
#include "IUiView.h"
#include "IElementModelShape.h"
#include "IModelView.h"
#include "IRegenerator.h"
#include "IElementPosition.h"
#include "IViewerContext.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"
#include "InstancePlacementTypes.h"
#include "IGraphicsStyleManager.h"
#include "UiViewUtils.h"
#include "GraphicsNodeUtils.h"
#include "ISymbolGraphicsElementShapeComponent.h"
#include "IPickTarget.h"
#include "IElementParameters.h"
#include "IOnePointInstanceOnHostInput.h"
#include "CommandParameters.h"
#include "IParameterDefinitionLibrary.h"

#include "UIWorkLevelUtilTemp.h"
#include "IGraphicsMaterialManager.h"
#include "IPickPointAction.h"
#include "IReferencePlane.h"
#include "IWorkPlane.h"
#include "IPlane.h"
#include "IGraphicsElementShape.h"
#include "GbmpGraphicsNodeUtils.h"
#include "ISnapContext.h"
#include "ISnapSettings.h"
#include "IPickResult.h"
#include "GcmpCommandState.h"
#include "ICanvas.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

//using namespace gfam;

CREATE_DEBUG_MODE(DisablePreviewOnInstanceCreation, L"创建族实例不显示预览效果",gcmp::DebugModeGroup::DMGT_INSTANCE_CREATION, L"GDMPLab", L"2023-12-20",
    L"打开这个调试标注位，在创建族实例时就不会显示预览效果！");

namespace
{
    //////////////////////////////////////////////////////////////////////////
    //拾取Host的过滤器，暂时只能拾取墙
    //////////////////////////////////////////////////////////////////////////
    class HostInstanceFilter : public IPickFilter
    {
    public:
        HostInstanceFilter(IDocument* pDoc)
            :m_pDocument(pDoc)
        {}
        virtual ~HostInstanceFilter() {}

        bool AllowElement(const ElementId& id) const override
        {
            //必须为Host
            IInstance* pInstance = quick_cast<IInstance>(m_pDocument->GetElement(id));
            if(pInstance == nullptr)
                return false;

            if(!pInstance->GetBasicInformation()->GetCategoryUid().IsValid() || pInstance->GetBasicInformation()->GetCategoryUid() != BuiltInCategoryUniIdentities::BICU_WALL)
                return false;

            return true;
        }

        bool AllowGraphicsNode(const IGraphicsNodeReference& nodeReference) const override
        {
            OwnerPtr<GraphicsNodeAndTransform> oNodeAndTransform = nodeReference.GetIntersectGraphicsNode();
            if(!oNodeAndTransform)
                return false;
            
            const IGraphicsNode* pNode = oNodeAndTransform->m_wpGraphicsNode.Get();
            if(!pNode)
                return false;

            if(pNode->GetVisibility() !=  gcmp::GraphicsNodeVisibility::Always)
                return false;

            return true;
        }

        bool SetPickTargetOption(IPickTarget* pickTarget) override
        {
            pickTarget->EnableGraphicsElementShape();
            return true;
        }
    private:
        IDocument *m_pDocument;
    };
}


//////////////////////////////////////////////////////////////////////////
//创建族实例的父Action，根据族类别的不同调用相应的子Action
//////////////////////////////////////////////////////////////////////////

CreateGBMPFamilyInstanceAction::CreateGBMPFamilyInstanceAction(const gcmp::ElementId& familyId, const std::wstring& familyType)
    : m_familyId(familyId)
    , m_familyType(familyType)
{
    m_createFamilyMethod = CFM_NOT_DEFIND;
}

CreateGBMPFamilyInstanceAction::~CreateGBMPFamilyInstanceAction()
{
}

void CreateGBMPFamilyInstanceAction::InitAction( IUiView* pCurrentView )
{
    IUiDocument* pUiDoc = pCurrentView->GetUiDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDoc, L"pUiDoc为空",L"GDMPLab",L"2024-03-30");
    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IElement* pElement = GetDoc()->GetElement(m_familyId);
    IFamily* family = quick_cast<IFamily>(pElement);
    DBG_WARN_AND_RETURN_VOID_UNLESS(family, L"family为空",L"GDMPLab",L"2024-03-30");

    InstancePlacementTypes posType = InstancePlacementTypes::Invalid;
    //获取放置类型参数

    const IFamilyType* pFamilyType = ((const IFamily*)family)->GetFamilyTypeByName(m_familyType);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pFamilyType != nullptr, L"族类型为空",L"GDMPLab",L"2024-03-30");
    const std::vector<OwnerPtr<IParameter>> parameters = pFamilyType->GetFamilyParameters();

    for (int i = 0; i < (int)parameters.size(); i++)
    {
        if (PARAMETER_UID(InstancePlacementTypeBuiltInParamter).HasSameValue(parameters[i]->GetParameterDefinitionUid()))
        {
            int posTypeTest = parameters[i]->GetValueAsInt();
            posType = (InstancePlacementTypes)parameters[i]->GetValueAsInt();
            break;
        }
    }

    gcmp::CommandParameters cmdParams;
    cmdParams[L"FamilyName"] = family->GetBasicInformation()->GetName();
    cmdParams[L"FamilyType"] = m_familyType;
    switch (posType)
    {
    case /*InstancePlacementTypes::*/InstancePlacementTypes::OnWorkPlane : //点式族、线式族放置方式
        {
            std::vector<Coordinate3d> coordSystem;
            //获取放置类型参数
            const IFamilyType* pTmpFamilyType = ((const IFamily*)family)->GetFamilyTypeByName(m_familyType);
            DBG_WARN_AND_RETURN_VOID_UNLESS(pTmpFamilyType != nullptr, L"族类型为空",L"GDMPLab",L"2024-03-30");
            const std::vector<OwnerPtr<IParameter>> parameters = pTmpFamilyType->GetFamilyParameters();

            for (int i = 0; i < (int)parameters.size(); i++)
            {
                if (PARAMETER_UID(CoordinateSystemBuiltInParameter).HasSameValue(parameters[i]->GetParameterDefinitionUid()))
                {
                    OwnerPtr<IParameter> tmpParam = parameters[i]->Clone();

                    const IParameterValueCurveByPoints* pPVSCoordinate =
                        dynamic_cast<const IParameterValueCurveByPoints*>(tmpParam->GetParameterValueStorage());

                    coordSystem = pPVSCoordinate->GetValue();
                    break;
                }
            }
            if (1 == coordSystem.size())    //点式族
            {
                ICommandManager::Get()->SendCommand(ID_CMD_CREATE_POINTFAMILY_INSTANCE_ON_WORKPLANE, cmdParams);
            }
            else if (2 == coordSystem.size())   //线式族
            {
                ICommandManager::Get()->SendCommand(ID_CMD_CREATE_LINEAR_INSTANCE, cmdParams);
            }
            else
            {
                MarkFinishStatus(ActionFinishStatus::Successful);
                DBG_WARN_AND_RETURN_VOID_UNLESS(false, L"不是点式族、线式族类型的常规构件",L"GDMPLab",L"2024-03-30");
            }
        }
        break;
    case /*InstancePlacementTypes::*/InstancePlacementTypes::OnHost:  //门、窗放置方式
        StartChildAction(NEW_AS_OWNER_PTR(ActionCreateOnePointInstanceOnHost, m_familyId, m_familyType));
        break;
    case /*InstancePlacementTypes::*/InstancePlacementTypes::OnLevel:
        {
            std::vector<Coordinate3d> coordSystem;
            //获取放置类型参数
            const IFamilyType* pTmpFamilyType = ((const IFamily*)family)->GetFamilyTypeByName(m_familyType);
            DBG_WARN_AND_RETURN_VOID_UNLESS(pTmpFamilyType != nullptr, L"族类型为空",L"GDMPLab",L"2024-03-30");
            const std::vector<OwnerPtr<IParameter>> parameters = pTmpFamilyType->GetFamilyParameters();
            for (int i = 0; i < (int)parameters.size(); i++)
            {
                if (PARAMETER_UID(CoordinateSystemBuiltInParameter).HasSameValue(parameters[i]->GetParameterDefinitionUid()))
                {
                    OwnerPtr<IParameter> tmpParam = parameters[i]->Clone();
                    const IParameterValueCurveByPoints* pPVSCoordinate =
                        dynamic_cast<const IParameterValueCurveByPoints*>(tmpParam->GetParameterValueStorage());
                    coordSystem = pPVSCoordinate->GetValue();
                    break;
                }
            }

            if (1 == (int)coordSystem.size())   //柱、楼梯、楼板放置方式
            {
                if ((BuiltInCategoryUniIdentities::BICU_COLUMN).HasSameValue(family->GetBasicInformation()->GetCategoryUid()))
                {
                }
                else
                {
                    StartChildAction(NEW_AS_OWNER_PTR(ActionCreateOnePointInstance, m_familyId, m_familyType));
                }
            }
            else if (2 == (int)coordSystem.size())  //墙、梁放置方式
            {
                ICommandManager::Get()->SendCommand(ID_CMD_CREATE_LINEAR_INSTANCE, cmdParams);
            }
            else    //没有设置BIC_MAGICAD_FAMILY放置方式
            {
                MarkFinishStatus(ActionFinishStatus::Successful);
                DBG_WARN_AND_RETURN_VOID_UNLESS(false, L"暂时不支持此种类别的族实例化",L"GDMPLab",L"2024-03-30");
            }
        }
        break;
    default:
        {
            MarkFinishStatus(ActionFinishStatus::Successful);
            DBG_WARN_AND_RETURN_VOID_UNLESS(false, L"暂时不支持此种类别的族实例化",L"GDMPLab",L"2024-03-30");
        }
        break;
    }
}

void CreateGBMPFamilyInstanceAction::OnChildActionFinished(IUiView* pCurrentView, const ActionOutput& childActionReturnParam)
{

    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView, L"pCurrentView为空",L"GDMPLab",L"2024-03-30");

    ICanvas *pCanvas = pCurrentView->GetCanvas();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCanvas != nullptr, L"ICanvas指针无效",L"GDMPLab",L"2024-03-30");
    pCanvas->Refresh();
    MarkFinishStatus(ActionFinishStatus::Successful);
}

//////////////////////////////////////////////////////////////////////////
//创建普通的点式族
//////////////////////////////////////////////////////////////////////////

ActionCreateOnePointInstance::ActionCreateOnePointInstance(const gcmp::ElementId& familyId, const std::wstring& familyType, bool continueCreate)
    : m_isUserCancelled(false)
    , m_isPreview(true)
    , m_familyId(familyId)
    , m_familyType(familyType)
    , m_continueCreate(continueCreate)
{
    if(DEBUG_MODE(DisablePreviewOnInstanceCreation))
    {
        m_isPreview = false;
    }
}

ActionCreateOnePointInstance::~ActionCreateOnePointInstance()
{
    CleanupTempGraphicsShape();
}

void ActionCreateOnePointInstance::InitAction(IUiView* pCurrentView)
{
    GettingInstancePlacePoint();
}
namespace
{
    ElementId GetReferencePlaneIdOfWorkPlane(const IModelView* pModelView)
    {
        DBG_WARN_AND_RETURN_UNLESS(pModelView, ElementId::InvalidID, L"pModelView为空",L"GDMPLab",L"2024-03-30");

        const IWorkPlane* pWorkPlane = quick_cast<IWorkPlane>(pModelView->GetDocument()->GetElement(pModelView->GetWorkPlaneId()));
        if (pWorkPlane != nullptr)
        {
            IReferencePlane* pRefPlane = quick_cast<IReferencePlane>(pModelView->GetDocument()->GetElement(pWorkPlane->GetReferencedPlaneId()));
            if (pRefPlane != nullptr)
            {
                return pWorkPlane->GetReferencedPlaneId();
            }
        }

        return ElementId::InvalidID;
    }
}

namespace
{
    Coordinate3d GetWorkPlaneCoordinate(const IModelView* pModelView)
    {
        Coordinate3d coord;
        DBG_WARN_AND_RETURN_UNLESS(pModelView, coord, L"pModelView为空",L"GDMPLab",L"2024-03-30");

        OwnerPtr<IPlane> pPlane = pModelView->GetWorkPlane();
        DBG_WARN_AND_RETURN_UNLESS(pPlane, coord, L"pPlane为空",L"GDMPLab",L"2024-03-30");

        return pPlane->GetCoordinate();
    }
}

void ActionCreateOnePointInstance::OnChildActionFinished(IUiView* pCurrentView, const ActionOutput& childActionReturnParam)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(nullptr != pCurrentView, L"pCurrentView为空",L"GDMPLab",L"2024-03-30");
    if(m_isUserCancelled)
    {
        // 如果用户选择退出
        CleanupTempGraphicsShape();
        MarkFinishStatus(ActionFinishStatus::Successful);
        UpdateView();
        return;
    }

    IModelView* pView = pCurrentView->GetModelView();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pView != nullptr, L"无效的pView",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pView->GetDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"无效的文档",L"GDMPLab",L"2024-03-30");

    gcmp::OwnerPtr<IUserTransaction> ut = IUserTransaction::Create(pDoc, (GBMP_TR(L"创建GBMP普通点式族实例")));
    DBG_WARN_AND_RETURN_VOID_UNLESS(ut != nullptr, L"无效ut",L"GDMPLab",L"2024-03-30");

    ElementId baseId = GetReferencePlaneIdOfWorkPlane(pView);
    if(!baseId.GetIsValidId())
        baseId = UIWorkLevelUtilTemp::GetWorkLevelId(pView);
    
    OwnerPtr<IOnePointInstanceInput> opOnePointInstanceInput = IOnePointInstanceInput::Create(pDoc, baseId, m_familyId, m_familyType);
    opOnePointInstanceInput->SetWorkPlaneCoordinate3d(GetWorkPlaneCoordinate(pView));
    opOnePointInstanceInput->SetPosition(Vector3d::Create(m_placePt.X(), m_placePt.Y(), m_placePt.Z()));
    opOnePointInstanceInput->SetTopAssociatedPlaneId(ElementId::CreateInvalidId());

    gcmp::IInstance* pInstance = IInstance::CreateByOnePoint(opOnePointInstanceInput.get());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pInstance, L"instance为空",L"GDMPLab",L"2024-03-30");

    ut->Commit();

    UpdateView();
    if (!m_continueCreate)
    {
        MarkFinishStatus(ActionFinishStatus::Successful);
        return;
    }
   GettingInstancePlacePoint();
}

void ActionCreateOnePointInstance::GettingInstancePlacePoint()
{
    SetPromptMessage(GBMP_TR(L"族的实例化：请输入族实例的放置点"));

    m_isUserCancelled = false;

    gcmp::OwnerPtr<IPickPointAction> upPickPointAction(IPickPointAction::Create( 
        PickPointExchangeData(&m_placePt, &m_isUserCancelled, &m_pickedPoints)
        , IPickPointAction::CreateMoveCallback(&ActionCreateOnePointInstance::PreviewByPlacePoint, this)));
    StartChildAction(TransferOwnership(upPickPointAction));
}

void ActionCreateOnePointInstance::PreviewByPlacePoint(IUiView* pCurrentView, const gcmp::Vector3d& pos, const gcmp::Vector3d& mousePt)
{
    if(!m_isPreview)
        return;

    IUiDocument* pUiDoc = pCurrentView->GetUiDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDoc, L"pUiDoc为空",L"GDMPLab",L"2024-03-30");
    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IModelView* view = pCurrentView->GetModelView();
    DBG_WARN_AND_RETURN_VOID_UNLESS(view, L"view为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IUserTransaction> ut = IUserTransaction::Create(pDoc, GBMP_TR(L"创建GBMP普通点式族实例"));
    DBG_WARN_AND_RETURN_VOID_UNLESS(ut, L"ut为空",L"GDMPLab",L"2024-03-30");

    ElementId baseId = GetReferencePlaneIdOfWorkPlane(view);
    if(!baseId.GetIsValidId())
    {
        baseId = UIWorkLevelUtilTemp::GetWorkLevelId(view);
    }

    OwnerPtr<IOnePointInstanceInput> opOnePointInstanceInput = IOnePointInstanceInput::Create(pDoc, baseId, m_familyId, m_familyType);
    opOnePointInstanceInput->SetPosition(pos);
    opOnePointInstanceInput->SetWorkPlaneCoordinate3d(GetWorkPlaneCoordinate(view));
    opOnePointInstanceInput->SetHeight(-1.0);
    opOnePointInstanceInput->SetCanBeShared(false);

    IInstance* assistInstance = IInstance::CreateByOnePoint(opOnePointInstanceInput.get());
    DBG_WARN_AND_RETURN_VOID_UNLESS(assistInstance, L"instance为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IGraphicsElementShape> tempGrep = TransferOwnershipCast<IGraphicsElementShape>(assistInstance->GetElementModelShape()->GetGraphicsElementShape()->Clone());
    DBG_WARN_AND_RETURN_VOID_UNLESS(tempGrep != nullptr, L"无效的tempGrep指针",L"GDMPLab",L"2024-03-30");
    OwnerPtr<IGraphicsNodeGroup> tempGpGrep = gcmp::GbmpGraphicsNodeUtils::TransferGRepToGGroup(TransferOwnership(tempGrep));
    DBG_WARN_AND_RETURN_VOID_UNLESS(tempGpGrep != nullptr, L"无效的tempGpGrep指针",L"GDMPLab",L"2024-03-30");
    tempGpGrep->SetIsSnappable(false);

   ut->Rollback();

    if(nullptr != tempGpGrep)
    {
        // 如果 IGraphicsElementShape 在事务中创建且事务被撤消了，那么 IGraphicsElementShape 上的样式或者材质的 ElementId 可能就引用到了一个被销毁的 Element 对象上（族文档中有样式或材质被映射到主文档）
        // 下面的代码是将 IGraphicsElementShape 上的样式和材质的 ElementId 全部清空，并将 IGraphicsElementShape 以“临时对象样式”进行渲染
        if (pDoc)
        {
            GraphicsNodeUtils::CleanGraphicsNodeStyleAndMaterial(pDoc, tempGpGrep.get());
            const IGraphicsMaterialManager* pMaterialMgr = pDoc->GetGraphicsMaterialManager();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pMaterialMgr, L"pStyleMgr为空。",L"GDMPLab",L"2024-03-30");
            tempGpGrep->SetGraphicsStyleId(pMaterialMgr->GetGraphicsMaterialIdByCategoryUid(BuiltInCategoryUniIdentities::BICU_TEMP_STYLE));
        }
        else
        {
            DBG_WARN(L"pDoc == nullptr",L"GDMPLab",L"2024-03-30");
        }

        DrawTempGraphicsNodeGroup(TransferOwnership(tempGpGrep));
    }
}

//////////////////////////////////////////////////////////////////////////
//创建基于Host对象的门窗族
//////////////////////////////////////////////////////////////////////////

ActionCreateOnePointInstanceOnHost::ActionCreateOnePointInstanceOnHost(const gcmp::ElementId& familyId, const std::wstring& familyType)
    : m_isUserCancelled(false)
    , m_isPreview(true)
    , m_familyId(familyId)
    , m_familyType(familyType)
    , m_snap(nullptr)
{
    if(DEBUG_MODE(DisablePreviewOnInstanceCreation))
    {
        m_isPreview = false;
    }
}
ActionCreateOnePointInstanceOnHost::~ActionCreateOnePointInstanceOnHost()
{
    CleanupTempGraphicsShape();
}

void ActionCreateOnePointInstanceOnHost::InitAction(IUiView* pCurrentView)
{
    GettingInstancePlacePoint();
}
namespace
{
    // 业务自己逻辑，从CreateInstanceUtility拷贝过来。
    bool GetPositionAndWallId(const IModelView* pCurrentView, const gcmp::IGraphicsNodeReference& pickResult, const ElementId& familyId, const std::wstring& familyType, Vector3d& pos, ElementId& wallId)
    {
        DBG_WARN_AND_RETURN_UNLESS(pCurrentView != nullptr, false, L"视图指针无效",L"GDMPLab",L"2024-03-30");
        IDocument* pDoc = pCurrentView->GetDocument();
        DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr, false, L"无效的文档指针",L"GDMPLab",L"2024-03-30");

        IFamily * pFamily = quick_cast<IFamily>(pDoc->GetElement(familyId));
        DBG_WARN_AND_RETURN_UNLESS(pFamily, false, L"获得族失败",L"GDMPLab",L"2024-03-30");

        wallId = pickResult.GetElementId();
        pos = pickResult.GetTransformedIntersectPoint();
        const std::wstring& viewType = pCurrentView->GetUserDataId();


        //需要获得窗族的窗台高度
        double windowSillHeight = 0;
        OwnerPtr<IParameter> windowSillHeightParam = pFamily->GetElementParameters()->GetParameterByUid(PARAMETER_UID(WindowSillHeightBuiltInParameter));
        if (windowSillHeightParam.get() && windowSillHeightParam->IsValidDocumentParameter() && viewType == L"PlanViewType")
        {
            //可能是窗，门的窗台高度默认为0
            windowSillHeight = windowSillHeightParam->GetValueAsDouble();
        }

        if (viewType == L"PlanViewType")
        {
            pos.Set(pos.X(), pos.Y(), GetWorkPlaneCoordinate(pCurrentView).Origin().Z() + windowSillHeight);
        }

        return true;
    }
}

namespace 
{
    // 业务自己代码，从CreateInstanceUtility拷出来。
    bool SetWindowSillHeightParameter(const IModelView* pCurrentView, const Vector3d& pos, IInstance* pInstance)
    {
        DBG_WARN_AND_RETURN_UNLESS(pCurrentView, false, L"视图指针无效",L"GDMPLab",L"2024-03-30");
        DBG_WARN_AND_RETURN_UNLESS(pInstance, false, L"视图指针无效",L"GDMPLab",L"2024-03-30");

        OwnerPtr<IParameter> windowSillHeightParam = ELEMENT_PARAMETER(pInstance, WindowSillHeightBuiltInParameter);
        if (IParameter::IsValidParameter(windowSillHeightParam) && pCurrentView->GetUserDataId() != L"PlanViewType")

        {
            //不在楼层平面视图，需要用窗实际放置的位置更新窗实例的窗台高度
            windowSillHeightParam->SetValueAsDouble(pos.Z() - GetWorkPlaneCoordinate(pCurrentView).Origin().Z());
            pInstance->GetElementParameters()->SetParameter(windowSillHeightParam.get());
        }

        return true;
    }
}
void ActionCreateOnePointInstanceOnHost::OnChildActionFinished(IUiView* pCurrentView, const ActionOutput& childActionReturnParam)
{
    if(m_isUserCancelled)
    {
        // 如果用户选择退出
        CleanupTempGraphicsShape();
        MarkFinishStatus(ActionFinishStatus::Successful);
        UpdateView();
        return;
    }

    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView != nullptr, L"无效的pCurrentView指针",L"GDMPLab",L"2024-03-30");

    IUiDocument* pUiDoc = pCurrentView->GetUiDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDoc, L"pUiDoc为空",L"GDMPLab",L"2024-03-30");
    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"无效的文档指针",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IGraphicsNodeReference> pickResult = IGraphicsNodeReference::Create();
    bool bRet = GetPickResult(pDoc, pCurrentView, m_placePt, *pickResult);
    if (!bRet)
    {
        GettingInstancePlacePoint();
        return;
    }

    Vector3d pos;
    ElementId wallId;
    GetPositionAndWallId(pCurrentView->GetModelView(), *pickResult, m_familyId, m_familyType, pos, wallId);

    OwnerPtr<IUserTransaction> ut = IUserTransaction::Create(pDoc, GBMP_TR(L"创建GBMP基于Host的点式族实例"));
    DBG_WARN_AND_RETURN_VOID_UNLESS(ut, L"ut为空",L"GDMPLab",L"2024-03-30");
    OwnerPtr<IOnePointInstanceInput> opInput = IOnePointInstanceInput::Create(pDoc, ElementId::InvalidID, m_familyId, m_familyType);
    DBG_WARN_AND_RETURN_VOID_UNLESS(opInput, L"opInput为空",L"GDMPLab",L"2024-03-30");
    opInput->SetPosition(pos);
    opInput->SetHostInstanceId(wallId);
    IInstance* instance = IInstance::CreateByOnePoint(opInput.get());
    DBG_WARN_AND_RETURN_VOID_UNLESS(instance, L"instance为空",L"GDMPLab",L"2024-03-30");

    SetWindowSillHeightParameter(pCurrentView->GetModelView(), pos, instance);

    ElementId id = instance->GetBasicInformation()->GetElementId();
    DBG_WARN_AND_RETURN_VOID_UNLESS(id.IsValid(), L"invalid object id",L"GDMPLab",L"2024-03-30");
    if(id.IsValid())
    {
       ut->Commit();
    }
    else
    {
       ut->Rollback();
    }
    UpdateView();
    GettingInstancePlacePoint();
}

void ActionCreateOnePointInstanceOnHost::GettingInstancePlacePoint()
{
    SetPromptMessage(GBMP_TR(L"族的实例化：请输入族实例的放置点"));

    m_isUserCancelled = false;
    m_snap = nullptr;
    gcmp::OwnerPtr<IPickPointAction> upPickPointAction(IPickPointAction::Create( 
        PickPointExchangeData(&m_placePt, &m_isUserCancelled, &m_pickedPoints, &m_snap)
        , IPickPointAction::CreateMoveCallback(&ActionCreateOnePointInstanceOnHost::PreviewByPlacePoint, this)));

    // 新捕捉定制
    OwnerPtr<gcmp::ISnapContext> snapContext = ISnapContext::Create();

    // 新捕捉选项设置
    OwnerPtr<ISnapSettings> snapSettings = snapContext->GetSnapSettings();
    snapSettings->SetIsSnapOff(true);
    snapContext->SetSnapSettings(snapSettings.get());

    upPickPointAction->SetSnapContext(snapContext.get());

    StartChildAction(TransferOwnership(upPickPointAction));
}

void ActionCreateOnePointInstanceOnHost::PreviewByPlacePoint(IUiView* pCurrentView, const gcmp::Vector3d& pos, const gcmp::Vector3d& mousePt)
{
    if(!m_isPreview)
        return;
    CreateTempOpeningByOnePointOnHost(pCurrentView, pos);
}

bool ActionCreateOnePointInstanceOnHost::CreateTempOpeningByOnePointOnHost(IUiView* pCurrentView, const gcmp::Vector3d& pos)
{
    IUiDocument* pUiDoc = pCurrentView->GetUiDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pUiDoc, L"pUiDoc为空",L"GDMPLab",L"2024-03-30");
    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc != nullptr, L"无效的文档指针",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IGraphicsNodeReference> pickResult = IGraphicsNodeReference::Create();
    bool bRet = GetPickResult(pDoc, pCurrentView, pos, *pickResult);
    //未拾取到 返回
    if (!bRet)
    {
        CleanupTempGraphicsShape();
        return false;
    }

    Vector3d intersectPt;
    ElementId wallId;
    GetPositionAndWallId(pCurrentView->GetModelView(), *pickResult, m_familyId, m_familyType, intersectPt, wallId);

    OwnerPtr<IUserTransaction> ut = IUserTransaction::Create(pDoc, GBMP_TR(L"创建GBMP基于Host的点式族实例"));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(ut, L"ut为空",L"GDMPLab",L"2024-03-30");
    OwnerPtr<IOnePointInstanceInput> opInput = IOnePointInstanceInput::Create(pDoc, ElementId::InvalidID, m_familyId, m_familyType);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(opInput, L"opInput为空",L"GDMPLab",L"2024-03-30");
    opInput->SetPosition(pos);
    opInput->SetHostInstanceId(wallId);
    IInstance* pOpeningInstance = IInstance::CreateByOnePoint(opInput.get());
    DBG_WARN_AND_RETURN_UNLESS(pOpeningInstance, false, L"instance为空",L"GDMPLab",L"2024-03-30");

    SetWindowSillHeightParameter(pCurrentView->GetModelView(), intersectPt, pOpeningInstance);

    if (pOpeningInstance)
    {
        pDoc->GetRegenerator()->RegenerateDocument();
    }
    else
    {
       ut->Rollback();
        return false;
    }
    DBG_WARN_AND_RETURN_UNLESS(pOpeningInstance != nullptr, false, L"无效的pOpeningInstance指针",L"GDMPLab",L"2024-03-30");
    const IGraphicsElementShape* temSymbolGRep = pOpeningInstance->GetSymbolGraphicsElementShapeComponent()->GetSymbolGraphicsElementShape();
    if (temSymbolGRep == NULL)
    {
        return false;
    }

    OwnerPtr<IGraphicsElementShape> symbolGrep = TransferOwnershipCast<IGraphicsElementShape>(pOpeningInstance->GetSymbolGraphicsElementShapeComponent()->GetSymbolGraphicsElementShape()->Clone());
    const IElementPosition *posBehavior = pOpeningInstance->GetElementPosition();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(posBehavior, L"无效的指针posBehavior",L"GDMPLab",L"2024-03-30");
    Matrix4d instanceTrans = posBehavior->ComputeLocalToWorldCoordinateSystemTransformMatrix();
    if (!instanceTrans.IsIdentity())
        symbolGrep->Transform(instanceTrans);
    OwnerPtr<IGraphicsNodeGroup> symbolGpGrep = gcmp::GbmpGraphicsNodeUtils::TransferGRepToGGroup(TransferOwnership(symbolGrep));
    ut->Rollback();
        
    GraphicsNodeUtils::CleanGraphicsNodeStyleAndMaterial(pDoc, symbolGpGrep.get());
    const IGraphicsStyleManager* pStyleManager = pDoc->GetGraphicsStyleManager();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pStyleManager, L"IGraphicsStyleManager为空",L"GDMPLab",L"2024-03-30");
    symbolGpGrep->SetGraphicsStyleId(pStyleManager->GetGraphicsStyleIdByCategoryUid(BuiltInCategoryUniIdentities::BICU_TEMP_STYLE));

    DrawTempGraphicsNodeGroup(TransferOwnership(symbolGpGrep));
    UpdateView();
    return true;
}

bool ActionCreateOnePointInstanceOnHost::GetPickResult(IDocument* pDocument, IUiView* pCurrentView, const Vector3d& pos, IGraphicsNodeReference& gnodeReference) const
{
    OwnerPtr<ILine3d> ray = UiViewUtility::WorldPositionToWorldRay(pCurrentView, pos);

    DBG_WARN_AND_RETURN_UNLESS(pCurrentView != nullptr, false, L"当前视图为空",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_UNLESS(pCurrentView->GetModelView() != nullptr, false, L"ModelView为空",L"GDMPLab",L"2024-03-30");
    std::vector<const IGraphicsElementShape*> greps = pCurrentView->GetVisibleGreps();

    IUiDocument* pUiDoc = pCurrentView->GetUiDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pUiDoc, L"pUiDoc为空",L"GDMPLab",L"2024-03-30");
    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IPickFilter> pPickFilter(NEW_AS_OWNER_PTR(HostInstanceFilter, pDoc));
    double tolerance = UiViewUtility::GetPickTolerance(pCurrentView);

    OwnerPtr<IPickTarget> pickTarget = IPickTarget::Create();
    pickTarget->EnableFace();
    OwnerPtr<IPointPickContext> pickContext = IPointPickContext::Create();
    pickContext->SetDocument(pDocument);
    pickContext->SetViewerContext(TransferOwnership(pCurrentView->GetViewerContext()));
    pickContext->SetGraphicsElementShapes(greps);
    pickContext->SetRay(ray.get());
    pickContext->SetPickTolerance(tolerance);
    pickContext->SetPickTarget(TransferOwnership(pickTarget));
    pickContext->SetPickFilter(pPickFilter.get());
    OwnerPtr<IPickResult> pickResults = IPicker::PickByPoint(pickContext.get());
    if (pickResults->IsEmpty())
        return false;

    // 虽然拾取到了，但是现在的面可能是已经被切割过的。既然我们知道了拾取到的Element，现在可以直接拿它的BaseGrep出来求交了
    IElement* pElement = pDoc->GetElement( pickResults->GetFront()->GetElementId());
    if(dynamic_cast<IInstance*>(pElement) == nullptr)
        return false;

    //这个Action不用了，这里也是业务的行为，PickByPoint4InstanceBaseGRep只有一处使用，暂时不暴露API
    //PickResult pickResults4Instance = Picker::PickByPoint4InstanceBaseGRep(*quick_cast<PointPickContext>(pickContext.get()));
    //if(pickResults4Instance.IsEmpty())
    //    return false;

    //gnodeReference.Set(*(pickResults4Instance.GetFront()));
    return true;
}

CreateGBMPFamilyInstanceCmd::CreateGBMPFamilyInstanceCmd()
    : Super(ID_CMD_CREATE_FAMILY_INSTANCE)
{

}

CreateGBMPFamilyInstanceCmd::~CreateGBMPFamilyInstanceCmd()
{

}

namespace
{
    //柱的类型: 垂直柱、斜柱
    enum EnColumnType
    {
        TYPE_VERTICAL = 0,    //垂直柱
        TYPE_SLANTED = 1     //斜柱
    };
}

gcmp::OwnerPtr<IAction> CreateGBMPFamilyInstanceCmd::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    DBG_WARN_AND_RETURN_UNLESS(cmdParams.size() == 2, nullptr, L"CreateGBMPFamilyInstanceCmd命令参数个数不正确",L"GDMPLab",L"2024-03-30");
    auto itor = cmdParams.find(L"FamilyName");
    DBG_WARN_AND_RETURN_UNLESS(itor != cmdParams.end(), nullptr, L"所需的参数不存在",L"GDMPLab",L"2024-03-30");
    std::wstring familyName = itor->second.AsWString();

    itor = cmdParams.find(L"FamilyType");
    DBG_WARN_AND_RETURN_UNLESS(itor != cmdParams.end(), nullptr, L"所需的参数不存在",L"GDMPLab",L"2024-03-30");
    std::wstring familyTypeName = itor->second.AsWString();

    DBG_WARN_AND_RETURN_UNLESS(!familyName.empty() && !familyTypeName.empty(), nullptr, L"CreateGBMPFamilyInstanceCmd命令参数值不正确",L"GDMPLab",L"2024-03-30");

    IUiDocumentViewManager *pUiDocManager = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDocManager, L"pUiDocManager 为空！",L"GDMPLab",L"2024-03-30");
    IUiDocument *pUiDocument = pUiDocManager->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDocument, L"pUiDocManager 为空！",L"GDMPLab",L"2024-03-30");
    gcmp::IDocument* pDoc = pUiDocument->GetDbDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"文档为空",L"GDMPLab",L"2024-03-30");

    IFamily* pFamily = IFamily::GetFamilyByName(pDoc, familyName);
    const IFamilyType* familyType = nullptr;
    if (pFamily)
    {
        familyType = ((const IFamily*)pFamily)->GetFamilyTypeByName(familyTypeName);
    }
    DBG_WARN_AND_RETURN_UNLESS(pFamily && familyType, nullptr, L"CreateGBMPFamilyInstanceCmd命令参数值不正确",L"GDMPLab",L"2024-03-30");

    auto familyCategoryUid = pFamily->GetBasicInformation()->GetCategoryUid();
    gcmp::OwnerPtr<IAction> pAction = NEW_AS_OWNER_PTR(CreateGBMPFamilyInstanceAction, pFamily->GetBasicInformation()->GetElementId(), familyTypeName);

    std::map<int, std::wstring> commandData;
    commandData.insert(std::make_pair((int)CMDDATATYPE_FAMILY_NAME, familyName));
    commandData.insert(std::make_pair((int)CMDDATATYPE_FAMILY_TYPE_NAME, familyTypeName));
    commandData.insert(std::make_pair((int)CMDDATATYPE_BUILTIN_CATEGORY_ID, familyCategoryUid.GetGuidString()));
    commandData.insert(std::make_pair((int)CMDDATATYPE_COMMAND_STRING, GetCommandId()));
    if ((BuiltInCategoryUniIdentities::BICU_COLUMN).HasSameValue(familyCategoryUid))
    {
        commandData.insert(std::make_pair((int)CMDDATATYPE_COLUMN_TYPE, StringUtil::ToWString((int)TYPE_VERTICAL)));
    }
    SaveCurrentCommandData(commandData);
    return pAction;
}

bool CreateGBMPFamilyInstanceCmd::IsEnabled() const
{
    if(!CommandBase::IsEnabled())
        return false;
    return gcmp::GcmpCommandState::IsInProjectEnvironment() && !gcmp::GcmpCommandState::IsInAnimationEnvironment();
}
bool CreateGBMPFamilyInstanceCmd::IsVisible() const
{
    return gcmp::GcmpCommandState::IsInProjectEnvironment() && !gcmp::GcmpCommandState::IsInAnimationEnvironment();
}

void RegisterCreateGBMPFamilyInstanceCmdCommand()
{
    ICommandManager::Get()->RegisterCommand(TR_MODULE_NAME, NEW_AS_OWNER_PTR(CreateGBMPFamilyInstanceCmd));
}
ONE_TIME_INITIALIZER(RegisterCreateGBMPFamilyInstanceCmdCommand)
